﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Reflection;

namespace Happy.Primitive
{
    /// <summary>
    /// 值类型语义类型的父类。
    /// </summary>
    public abstract class ValueTypeBase<TValueObject> : IEquatable<TValueObject>
        where TValueObject : ValueTypeBase<TValueObject>
    {
        /// <inheritdoc />
        public bool Equals(TValueObject other)
        {
            if ((object)other == null)
            {
                return false;
            }

            if (object.ReferenceEquals(this, other))
            {
                return true;
            }

            var publicProperties = this.GetType().GetProperties();

            if (publicProperties.Any())
            {
                return publicProperties.All(p =>
                {
                    var left = p.GetValue(this, null);
                    var right = p.GetValue(other, null);

                    if (left is TValueObject)
                    {
                        return object.ReferenceEquals(left, right);
                    }

                    return object.Equals(left, right);
                });
            }

            return true;
        }

        /// <inheritdoc />
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (object.ReferenceEquals(this, obj))
            {
                return true;
            }

            var item = obj as ValueTypeBase<TValueObject>;

            return (object)item != null && this.Equals((TValueObject)item);
        }

        /// <inheritdoc />
        public override int GetHashCode()
        {
            int hashCode = 31;
            bool changeMultiplier = false;
            const int index = 1;

            var publicProperties = this.GetType().GetProperties();

            if (publicProperties.Any())
            {
                foreach (var item in publicProperties)
                {
                    var value = item.GetValue(this, null);

                    if (value != null)
                    {
                        hashCode = hashCode * ((changeMultiplier) ? 59 : 114) + value.GetHashCode();

                        changeMultiplier = !changeMultiplier;
                    }
                    else
                    {
                        hashCode = hashCode ^ (index * 13);
                    }
                }
            }

            return hashCode;
        }

        /// <inheritdoc />
        public static bool operator ==(ValueTypeBase<TValueObject> left, ValueTypeBase<TValueObject> right)
        {
            if (object.Equals(left, null))
            {
                return (object.Equals(right, null));
            }
            
            return left.Equals(right);
        }

        /// <inheritdoc />
        public static bool operator !=(ValueTypeBase<TValueObject> left, ValueTypeBase<TValueObject> right)
        {
            return !(left == right);
        }
    }
}
